class ScrollSpy {
    constructor(object) {

        if( typeof object.target !== "function" || typeof object.order !== "function" || typeof object.top !== "function" || typeof object.enter !== "function"){
            return;
        }


        let scrollSpyArr = document.getElementsByClassName("scrollSpy");

        this.delay = typeof object.delay ==="number" ? object.delay : 10;

        if (scrollSpyArr.length <= 0) {
            return;
        }

        for (let i = 0, len = scrollSpyArr.length; i < len; i++) {


            let scrollSpy = scrollSpyArr[i];

            let offset = scrollSpy.getAttribute("data-offset") ? scrollSpy.getAttribute("data-offset") : 0;
            let targetName = scrollSpy.getAttribute("data-target");

            if (!targetName) {
                return;
            }

            let scrollSpyItemArr = scrollSpy.getElementsByClassName("spy");

            if (scrollSpyItemArr.length <= 0) {
                return;
            }


            let navArr = this.getElements(targetName);//不想用 querySelectorAll()，就是喜欢瞎折腾。
            if (navArr.length <= 0) {
                return;
            }


            let navChildren;


            if (scrollSpy.tagName === "BODY") {

                //body 元素

                let myBrower = this.myBrowser();

                let windowObj;

                if (myBrower === "IE" || myBrower === "Firefox") {
                    windowObj = document.documentElement;
                } else {
                    windowObj = document.body;
                }


                for (let a = 0, b = navArr.length; a < b; a++) {

                    let navChildren = navArr[a].getElementsByClassName("spy-nav-item");

                    let isJump = false;

                    for (let n = 0, len = scrollSpyItemArr.length; n < len; n++) {

                        let i = n; //可恶的IE浏览器。

                        if (navChildren[i]) {

                            navChildren[i].addEventListener("click", function () {

                                if (isJump === true) {
                                    return false;
                                }

                                isJump = true;

                                let speed = (offset - scrollSpyItemArr[i].getBoundingClientRect().top) / 50;
                                let reg = /^((-?)\d+)(\.*\d+)?$/;
                                let res = reg.exec(speed.toString());
                                let num = 0;

                                let id = setInterval(function () {
                                    num++;
                                    windowObj.scrollTop -= parseFloat(res[1]);
                                    if (num === 50) {
                                        clearInterval(id);
                                        if (res[3]) {
                                            if (res[2]) {
                                                windowObj.scrollTop -= -parseFloat(res[3]) * 50 - 1;
                                            } else {
                                                windowObj.scrollTop -= parseFloat(res[3]) * 50 - 1;
                                            }
                                        }

                                        isJump = false;

                                    }

                                }, 10);

                            });
                        }

                    }

                }



                let arr1 = [];

                let arr2 = [];

                let p = 0, t = 0;

                let maxIndex = 0;


                if(windowObj.scrollTop === 0){

                    if(scrollSpyItemArr[0].getBoundingClientRect().top  <= offset){
                        for (let n = 0, m = navArr.length; n < m; n++) {
                            object.enter(navArr[n].getElementsByClassName("spy-nav-item")[0],navArr[n],scrollSpy);
                        }
                    }

                }else{

                    for (let i = 0, len = scrollSpyItemArr.length; i < len; i++) {
                        if (scrollSpyItemArr[i].getBoundingClientRect().top <= offset) {
                            maxIndex = i;
                        }
                    }

                    for (let n = 0, m = navArr.length; n < m; n++) {
                        navChildren = navArr[n].getElementsByClassName("spy-nav-item");
                        for (let a = 0, b = navChildren.length; a < b; a++) {
                            if (a === maxIndex) {
                                if(a === 0){
                                    if(scrollSpyItemArr[0].getBoundingClientRect().top > offset){
                                        arr1[0] = false;
                                    }else{
                                        object.target(a,navChildren[a],navArr[n],scrollSpy);
                                    }
                                }else if(a === navChildren.length-1){
                                    if(scrollSpyItemArr[scrollSpyItemArr.length-1].getBoundingClientRect().bottom  < offset){
                                        arr1[scrollSpyItemArr.length-1] = false;
                                    }else{
                                        object.target(a,navChildren[a],navArr[n],scrollSpy);
                                    }
                                }else{
                                    object.target(a,navChildren[a],navArr[n],scrollSpy);
                                }
                            } else {
                                object.order(a,navChildren[a],navArr[n],scrollSpy);
                            }
                        }
                    }
                }




                function handle(){

                    p = windowObj.scrollTop;

                    if (t <= p) {

                        arr2 = [];

                        for (let i = 0, len = scrollSpyItemArr.length; i < len; i++) {
                            if (scrollSpyItemArr[i].getBoundingClientRect().top <= offset) {
                                maxIndex = i;
                            }
                        }

                        if (!arr1[maxIndex]) {
                            arr1[maxIndex] = true;
                            for (let n = 0, m = navArr.length; n < m; n++) {
                                navChildren = navArr[n].getElementsByClassName("spy-nav-item");
                                for (let a = 0, b = navChildren.length; a < b; a++) {
                                    if (a === maxIndex) {
                                        if(a === 0){
                                            if(scrollSpyItemArr[0].getBoundingClientRect().top > offset){
                                                arr1[0] = false;
                                            }else{
                                                object.target(a,navChildren[a],navArr[n],scrollSpy);
                                            }
                                        }else if(a === navChildren.length-1){
                                            if(scrollSpyItemArr[scrollSpyItemArr.length-1].getBoundingClientRect().bottom  < offset){
                                                arr1[scrollSpyItemArr.length-1] = false;
                                            }else{
                                                object.target(a,navChildren[a],navArr[n],scrollSpy);
                                            }
                                        }else{
                                            object.target(a,navChildren[a],navArr[n],scrollSpy);
                                        }
                                    } else {
                                        object.order(a,navChildren[a],navArr[n],scrollSpy);
                                    }
                                }
                            }
                        }

                        if(scrollSpyItemArr[0].getBoundingClientRect().top > offset){
                            if(!arr1["top"]){
                                arr1["top"] = true;
                                for (let n = 0, m = navArr.length; n < m; n++) {
                                    navChildren = navArr[n].getElementsByClassName("spy-nav-item");
                                    for (let a = 0, b = navChildren.length; a < b; a++) {
                                        object.top(a,navChildren[a],navArr[n],scrollSpy);
                                    }
                                }
                            }
                        }

                        if(scrollSpyItemArr[scrollSpyItemArr.length-1].getBoundingClientRect().bottom < offset){
                            if(!arr1["bottom"]){
                                arr1["bottom"] = true;
                                for (let n = 0, m = navArr.length; n < m; n++) {
                                    navChildren = navArr[n].getElementsByClassName("spy-nav-item");
                                    for (let a = 0, b = navChildren.length; a < b; a++) {
                                        object.bottom(a,navChildren[a],navArr[n],scrollSpy);
                                    }
                                }
                            }
                        }



                    } else {

                        arr1 = [];

                        for (let i = 0, len = scrollSpyItemArr.length; i < len; i++) {
                            if (scrollSpyItemArr[i].getBoundingClientRect().top <= offset) {
                                maxIndex = i;
                            }
                        }

                        if (!arr2[maxIndex]) {
                            arr2[maxIndex] = true;
                            for (let n = 0, m = navArr.length; n < m; n++) {
                                navChildren = navArr[n].getElementsByClassName("spy-nav-item");
                                for (let a = 0, b = navChildren.length; a < b; a++) {
                                    if (a === maxIndex) {
                                        if(a === 0){
                                            if(scrollSpyItemArr[0].getBoundingClientRect().top > offset){
                                                arr2[0] = false;
                                            }else{
                                                object.target(a,navChildren[a],navArr[n],scrollSpy);
                                            }
                                        }else if(a === scrollSpyItemArr.length - 1){
                                            if(scrollSpyItemArr[scrollSpyItemArr.length-1].getBoundingClientRect().bottom  < offset){
                                                arr2[scrollSpyItemArr.length-1] = false;
                                            }else{
                                                object.target(a,navChildren[a],navArr[n],scrollSpy);
                                            }
                                        }else{
                                            object.target(a,navChildren[a],navArr[n],scrollSpy);
                                        }
                                    } else {
                                        object.order(a,navChildren[a],navArr[n],scrollSpy);
                                    }
                                }
                            }
                        }

                        if(scrollSpyItemArr[0].getBoundingClientRect().top > offset){
                            if(!arr2["top"]){
                                arr2["top"] = true;
                                for (let n = 0, m = navArr.length; n < m; n++) {
                                    navChildren = navArr[n].getElementsByClassName("spy-nav-item");
                                    for (let a = 0, b = navChildren.length; a < b; a++) {
                                        object.top(a,navChildren[a],navArr[n],scrollSpy);
                                    }
                                }
                            }
                        }

                        if(scrollSpyItemArr[scrollSpyItemArr.length-1].getBoundingClientRect().bottom < offset){
                            if(!arr2["bottom"]){
                                arr2["bottom"] = true;
                                for (let n = 0, m = navArr.length; n < m; n++) {
                                    navChildren = navArr[n].getElementsByClassName("spy-nav-item");
                                    for (let a = 0, b = navChildren.length; a < b; a++) {
                                        object.bottom(a,navChildren[a],navArr[n],scrollSpy);
                                    }
                                }
                            }
                        }
                    }

                    t = p;
                }


                window.addEventListener("scroll", this.throttle(handle,this.delay));

            } else {

                //普通元素

                for (let a = 0, b = navArr.length; a < b; a++) {

                    let navChildren = navArr[a].getElementsByClassName("spy-nav-item");

                    let isJump = false;

                    for (let n = 0, len = scrollSpyItemArr.length; n < len; n++) {

                        let i = n;

                        if(navChildren[i]){

                            navChildren[i].addEventListener("click", function () {

                                if (isJump === true) {
                                    return false;
                                }

                                isJump = true;

                                let targetScrollTop = scrollSpyItemArr[i].getBoundingClientRect().top - scrollSpy.getBoundingClientRect().top - offset;

                                let speed = (-targetScrollTop) / 50;

                                let reg = /^((-?)\d+)(\.*\d+)?$/;
                                let res = reg.exec(speed.toString());
                                let num = 0;

                                let id = setInterval(function () {
                                    num++;
                                    scrollSpy.scrollTop -= parseFloat(res[1]);
                                    if (num === 50) {
                                        clearInterval(id);

                                        if (res[3]) {
                                            if (res[2]) {
                                                scrollSpy.scrollTop -= -parseFloat(res[3]) * 50 - 1;
                                            } else {
                                                scrollSpy.scrollTop -= parseFloat(res[3]) * 50 - 1;
                                            }
                                        }

                                        isJump = false;

                                    }
                                }, 10);

                            });
                        }

                    }

                }

                if(scrollSpyItemArr[0].getBoundingClientRect().top - scrollSpy.getBoundingClientRect().top <= offset){
                    for (let n = 0, m = navArr.length; n < m; n++) {
                        object.enter(navArr[n].getElementsByClassName("spy-nav-item")[0],navArr[n],scrollSpy);
                    }
                }


                let arr1 = [];

                let arr2 = [];

                let p = 0, t = 0;

                let maxIndex = 0;


                function handle(){

                    p = scrollSpy.scrollTop;

                    if (t <= p) {

                        arr2 = [];

                        for (let i = 0, len = scrollSpyItemArr.length; i < len; i++) {

                            if (scrollSpyItemArr[i].getBoundingClientRect().top - scrollSpy.getBoundingClientRect().top <= offset) {
                                maxIndex = i;
                            }

                        }


                        if (!arr1[maxIndex]) {
                            arr1[maxIndex] = true;
                            for (let n = 0, m = navArr.length; n < m; n++) {
                                navChildren = navArr[n].getElementsByClassName("spy-nav-item");
                                for (let a = 0, b = navChildren.length; a < b; a++) {
                                    if (a === maxIndex) {
                                        if(a === 0){
                                            if(scrollSpyItemArr[0].getBoundingClientRect().top - scrollSpy.getBoundingClientRect().top > offset){
                                                arr1[0] = false;
                                            }else{
                                                object.target(a,navChildren[a],navArr[n],scrollSpy);
                                            }
                                        }else if(a === navChildren.length-1){
                                            if(scrollSpyItemArr[scrollSpyItemArr.length-1].getBoundingClientRect().bottom  - scrollSpy.getBoundingClientRect().top  < offset){
                                                arr1[scrollSpyItemArr.length-1] = false;
                                            }else{
                                                object.target(a,navChildren[a],navArr[n],scrollSpy);
                                            }
                                        }else{
                                            object.target(a,navChildren[a],navArr[n],scrollSpy);
                                        }
                                    } else {
                                        object.order(a,navChildren[a],navArr[n],scrollSpy);
                                    }
                                }
                            }
                        }


                        if(scrollSpyItemArr[0].getBoundingClientRect().top - scrollSpy.getBoundingClientRect().top > offset){
                            if (!arr1["top"]) {
                                arr1["top"] = true;
                                for (let n = 0, m = navArr.length; n < m; n++) {
                                    navChildren = navArr[n].getElementsByClassName("spy-nav-item");
                                    for (let a = 0, b = navChildren.length; a < b; a++) {
                                        object.top(a,navChildren[a],navArr[n],scrollSpy);
                                    }
                                }
                            }

                        }

                        if(scrollSpyItemArr[scrollSpyItemArr.length-1].getBoundingClientRect().bottom  - scrollSpy.getBoundingClientRect().top  < offset){
                            if (!arr1["bottom"]) {
                                arr1["bottom"] = true;
                                for (let n = 0, m = navArr.length; n < m; n++) {
                                    navChildren = navArr[n].getElementsByClassName("spy-nav-item");
                                    for (let a = 0, b = navChildren.length; a < b; a++) {
                                        object.bottom(a,navChildren[a],navArr[n],scrollSpy);
                                    }
                                }
                            }

                        }

                    } else {

                        arr1 = [];

                        for (let i = 0, len = scrollSpyItemArr.length; i < len; i++) {

                            if (scrollSpyItemArr[i].getBoundingClientRect().top - scrollSpy.getBoundingClientRect().top <= offset) {
                                maxIndex = i;
                            }

                        }

                        if (!arr2[maxIndex]) {
                            arr2[maxIndex] = true;
                            for (let n = 0, m = navArr.length; n < m; n++) {
                                navChildren = navArr[n].getElementsByClassName("spy-nav-item");
                                for (let a = 0, b = navChildren.length; a < b; a++) {
                                    if (a === maxIndex) {
                                        if(a === 0){
                                            if(scrollSpyItemArr[0].getBoundingClientRect().top - scrollSpy.getBoundingClientRect().top > offset){
                                                arr2[0] = false;
                                            }else{
                                                object.target(a,navChildren[a],navArr[n],scrollSpy);
                                            }
                                        }else if(a === scrollSpyItemArr.length-1){
                                            if(scrollSpyItemArr[scrollSpyItemArr.length-1].getBoundingClientRect().bottom  - scrollSpy.getBoundingClientRect().top  < offset){
                                                arr2[scrollSpyItemArr.length-1] = false;
                                            }else{
                                                object.target(a,navChildren[a],navArr[n],scrollSpy);
                                            }
                                        }else{
                                            object.target(a,navChildren[a],navArr[n],scrollSpy);
                                        }
                                    } else {
                                        object.order(a,navChildren[a],navArr[n],scrollSpy);
                                    }
                                }
                            }
                        }

                        if(scrollSpyItemArr[0].getBoundingClientRect().top - scrollSpy.getBoundingClientRect().top > offset){
                            if (!arr2["top"]) {
                                arr2["top"] = true;
                                for (let n = 0, m = navArr.length; n < m; n++) {
                                    navChildren = navArr[n].getElementsByClassName("spy-nav-item");
                                    for (let a = 0, b = navChildren.length; a < b; a++) {
                                        object.top(a,navChildren[a],navArr[n],scrollSpy);
                                    }
                                }
                            }
                        }


                        if(scrollSpyItemArr[scrollSpyItemArr.length-1].getBoundingClientRect().bottom  - scrollSpy.getBoundingClientRect().top  < offset){
                            if (!arr2["bottom"]) {
                                arr2["bottom"] = true;
                                for (let n = 0, m = navArr.length; n < m; n++) {
                                    navChildren = navArr[n].getElementsByClassName("spy-nav-item");
                                    for (let a = 0, b = navChildren.length; a < b; a++) {
                                        object.bottom(a,navChildren[a],navArr[n],scrollSpy);
                                    }
                                }
                            }
                        }
                    }

                    t = p;

                }

                scrollSpy.addEventListener("scroll",this.throttle(handle,this.delay));
            }


        }

    }

    getElements(_name) {

        let reg = /^(\.|#)(\S+)$/;
        let res = reg.exec(_name);
        let el;
        if (res) {
            if (res[1] === ".") {
                reg = /^[0-9]/;
                let name = res[2];
                res = reg.exec(res[2]);
                if (res === null) {
                    el = document.getElementsByClassName(name);
                } else {
                    throw new Error();
                }
            } else {
                reg = /^[0-9]/;
                let name = res[2];
                res = reg.exec(res[2]);
                if (res === null) {
                    el = document.getElementById(name);
                } else {
                    throw new Error();
                }
            }
        } else {
            reg = /^[A-z]+$/;
            res = reg.exec(_name);
            if (res) {
                el = document.getElementsByTagName(res[0]);
            } else {
                throw new Error();
            }
        }

        return el;
    }

    myBrowser() {

        let userAgent = navigator.userAgent; //取得浏览器的userAgent字符串
        if (userAgent.indexOf("Opera") > -1) {
            return "Opera" //判断是否Opera浏览器
        }
        if (userAgent.indexOf("Firefox") > -1) {
            return "Firefox"; //判断是否Firefox浏览器
        }
        if (userAgent.indexOf("Chrome") > -1) {
            return "Chrome";
        }
        if (userAgent.indexOf("Safari") > -1) {
            return "Safari"; //判断是否Safari浏览器
        }
        if ((userAgent.indexOf("compatible") > -1 && userAgent.indexOf("MSIE") > -1) || (userAgent.indexOf('Trident') > -1 && userAgent.indexOf("rv:11.0") > -1)) {
            return "IE"; //判断是否IE浏览器
        }

        if (userAgent.indexOf("Edge") > -1) {
            return "Edge";
        }

    }



    throttle (func, delay) {
        let prev = Date.now();
        return function() {
            let context = this;
            let args = arguments;
            let now = Date.now();
            if (now - prev >= delay) {
                func.apply(context, args);
                prev = Date.now();
            }
        }
    }



}